package com.kendoui.taglib;

import com.kendoui.taglib.json.Function;
import com.kendoui.taglib.json.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;

public abstract class BaseTag extends BodyTagSupport
  implements Serializable
{
  private Map<String, Object> json;

  public void setPageContext(PageContext context)
  {
    initialize();

    super.setPageContext(context);
  }

  public boolean isSet(String key) {
    return this.json.containsKey(key);
  }

  public void setEvent(String name, String body) {
    setProperty(name, new Function(body));
  }

  public String body() {
    BodyContent body = getBodyContent();

    if (body != null) {
      return body.getString();
    }

    return "";
  }

  public void initialize() {
    this.json = new HashMap();
  }

  public void destroy() {
    this.json = null;
  }

  public int doEndTag() throws JspException
  {
    destroy();

    return super.doEndTag();
  }

  public void setProperty(String key, double value) {
    this.json.put(key, Double.valueOf(value));
  }

  public void setProperty(String key, String value) {
    this.json.put(key, value);
  }

  public void setProperty(String key, boolean value) {
    this.json.put(key, Boolean.valueOf(value));
  }

  public void setProperty(String key, Object value) {
    this.json.put(key, valueOf(value));
  }

  protected Object valueOf(Object value) {
    if ((value instanceof Serializable))
      value = ((Serializable)value).properties();
    else if (value != null) {
      try {
        value = Double.valueOf(Double.parseDouble(value.toString()));
      }
      catch (NumberFormatException e)
      {
      }
    }
    return value;
  }

  public Object getProperty(String key) {
    return this.json.get(key);
  }

  public Map<String, Object> properties()
  {
    return this.json;
  }

  private static String tagName(Class<?> clazz) {
    Method tagName = null;
    try {
        tagName = clazz.getDeclaredMethod("tagName", (Class[])null);
        return new StringBuilder().append("<kendo:").append((String)tagName.invoke(null, (Object[])null)).append(">").toString();
      } catch (Exception e) {
      }
    return "";
  }

  public Object findParentWithClass(Class<?> clazz) throws JspException
  {
    Object parent = getParent();

    if ((parent == null) || (!clazz.isAssignableFrom(parent.getClass()))) {
      StringBuilder exception = new StringBuilder();

      String targetTagName = tagName(clazz);

      if (targetTagName.isEmpty()) {
        exception.append("The ").append(tagName(getClass())).append(" tag should be nested.");
      }
      else
      {
        exception.append("The ").append(tagName(getClass())).append(" tag should be nested in a ").append(tagName(clazz)).append(" tag.");
      }

      throw new JspException(exception.toString());
    }

    return parent;
  }
}